/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package z.h.w.jar.data.map;

import java.util.*;

/**
 *
 * @author EnzoZhong
 * @param <K>
 * @param <V>
 */
public class CacheMap<K , V> implements Map<K , V> {

     private Map<K , V> OUTER;
     private Map<K , V> INNER;
     private Integer max = new Double( +Runtime.getRuntime().maxMemory() / 1024 / 1024 / 2 ).intValue();

     /**
      *
      */
     public CacheMap () {
          OUTER = Collections.synchronizedMap( new HashMap<K , V>() );
          INNER = Collections.synchronizedMap( new WeakHashMap<K , V>() );
     }

     @Override
     public int size () {
          return OUTER.size() + INNER.size();
     }

     @Override
     public boolean isEmpty () {
          return OUTER.isEmpty() && INNER.isEmpty();
     }

     @Override
     public boolean containsKey ( Object key ) {
          return OUTER.containsKey( key ) || INNER.containsKey( key );
     }

     @Override
     public boolean containsValue ( Object value ) {
          throw new UnsupportedOperationException( "Not supported yet." );
     }

     @Override
     public V get ( Object key ) {
          K k = ( K ) key;
          if ( OUTER.containsKey( k ) ) {
               return OUTER.get( k );
          } else if ( INNER.containsKey( k ) ) {
               return INNER.get( k );
          } else {
               return null;
          }
     }

     @Override
     public V put ( K key , V value ) {
          OUTER.put( key , value );
          if ( OUTER.size() > max ) {
               INNER.putAll( OUTER );
               OUTER.clear();
          }
          return value;
     }

     @Override
     public V remove ( Object key ) {
          V v = OUTER.remove( key );
          INNER.remove( key );
          return v;
     }

     @Override
     public void putAll ( Map m ) {
          OUTER.putAll( m );
          if ( OUTER.size() >= max ) {
               INNER.putAll( OUTER );
               OUTER.clear();
          }
     }

     @Override
     public void clear () {
          OUTER.clear();
          INNER.clear();
     }

     @Override
     public Set keySet () {
          Set set = OUTER.keySet();
          set.addAll( INNER.keySet() );
          return set;
     }

     @Override
     public Collection values () {
          throw new UnsupportedOperationException( "Not supported yet." );
     }

     @Override
     public Set<Entry<K , V>> entrySet () {
          Set<Entry<K , V>> tmp = OUTER.entrySet();
          tmp.addAll( INNER.entrySet() );
          return tmp;
     }
}
